import {app, dialog} from 'electron'
import path from "path";

const os = require('os')
const fs = require('fs')
const util = require('util')
// const {exec} = require('child_process');
const cmd = require('node-cmd');
const mv = require('mv');
const moment = require('moment');
const winston = require('winston')
const parseString = require('xml2js').parseString;
const logger = winston.createLogger({
    transports: [new winston.transports.Console(), new winston.transports.File({filename: 'combined.log'})]
})

export async function handleSystem() {
    return process.platform
}

export async function handleMkvtoolnix() {
    let properties = ['openFile']
    if (process.platform === 'win32') {
        properties = ['openDirectory']
    }
    const {canceled, filePaths} = await dialog.showOpenDialog({properties});
    if (!canceled) {
        const homeDir = path.dirname(app.getPath('exe'))
        let confPath = homeDir
        if (process.platform === 'darwin') {
            confPath = `${homeDir}/conf.json`
        }
        if (process.platform === 'win32') {
            confPath = `${homeDir}\\conf.json`
        }
        fs.readFile(confPath, {encoding: 'UTF-8'}, (err, data) => {
            let json = {}
            if (!err) {
                json = JSON.parse(data)
            }
            json.mkvtoolnix = filePaths[0]

            fs.writeFile(confPath, JSON.stringify(json, null, 2), {}, (err) => {
                if (err) {
                    logger.error(err)
                } else {
                    logger.info(`保存到缓存配置:${confPath}`)
                }

            })
        })
        return filePaths[0]
    }
}

export async function handleFileOpen() {

    const {canceled, filePaths} = await dialog.showOpenDialog({
        properties: ['openFile', 'openDirectory'], filters: [{name: 'Movies', extensions: ['mkv']},]
    })
    if (canceled) {
        return
    } else {
        let mkvinfo = 'mkvinfo'
        if (process.platform === 'darwin') {
            mkvinfo = 'Contents/MacOS/' + mkvinfo
        }
        if (process.platform === 'win32') {
            mkvinfo = mkvinfo + ".exe"
        }
        let filesPath = []
        if (fs.statSync(filePaths[0]).isDirectory()) {
            const listFile = (dir) => {
                const arr = fs.readdirSync(dir);
                arr.forEach(function (item) {
                    const fullPath = path.join(dir, item);
                    const stats = fs.statSync(fullPath);
                    if (stats.isDirectory()) {
                        listFile(fullPath);
                    } else if (fullPath.endsWith(".mkv")) {
                        filesPath.push(fs.createReadStream(fullPath));
                    }
                });
                return filesPath;
            }
            filesPath = listFile(filePaths[0])
        } else {
            filesPath.push(fs.createReadStream(filePaths[0]))
        }


        return filesPath
    }
}

export function handleStart(event, mkvtoolnix, list, threadCount = os.cpus().length, win) {
    const l = JSON.parse(list);
    let mkvmerge = 'mkvmerge'
    if (process.platform === 'darwin') {
        mkvmerge = `${mkvtoolnix}/Contents/MacOS/mkvmerge`
    }
    let language = ''
    if (process.platform === 'win32') {
        mkvmerge = `${mkvtoolnix}\\mkvmerge.exe`
        language = ' --ui-language en'
    }
    const sendMsg = msg => {
        win.webContents.send('update-result', msg)
    }
    const filter = l.filter(i => i.indeterminate || i.checked);
    const runNext = thisIndexs => {

        let maxIndex = -1
        const finishKeys = [];
        if (thisIndexs && thisIndexs.length) {
            maxIndex = Math.max(...thisIndexs)
            for (let i = 0; i < thisIndexs.length; i++) {
                const key = filter[thisIndexs[i]].key
                let size = 0;
                const stat = fs.statSync(key)
                if (stat) {
                    size = stat.size
                }
                finishKeys.push({key, size})
            }
        }
        const nextIndexs = []
        for (let i = maxIndex + 1; i < filter.length && i <= maxIndex + threadCount; i++) {
            nextIndexs.push(i)
        }
        let finishPercent = parseInt(((maxIndex / filter.length) * 100) + '');
        if (finishPercent < 0) {
            finishPercent = 0
        }
        win.webContents.send('update-finishPercent', {
            finishPercent: finishPercent,
            finishCount: maxIndex < 0 ? 0 : maxIndex,
            allCount: filter.length,
            finishKeys: finishKeys
        })
        if (nextIndexs.length) {
            run(nextIndexs)
        } else {
            sendMsg(`${filter.length}个文件全部完成.`)
            win.webContents.send('update-finish',)
        }
    }
    const run = indexs => {
        try {
            const cmdRunPromises = [];
            for (let i = 0; i < indexs.length; i++) {
                const index = indexs[i]
                const o = filter[index];
                try {
                    const newPath = `${o.path}.temp`
                    let command = `"${mkvmerge}"${language} -o "${newPath}"`
                    const vArr = []
                    const aArr = []
                    const tArr = []
                    for (let j = 0; j < o.children.length; j++) {
                        const child = o.children[j];
                        const id = parseInt(child.id) - 1;
                        if (child.checked) {
                            if (child.type === 'v') {
                                vArr.push(id)
                            }
                            if (child.type === 'a') {
                                aArr.push(id)
                            }
                            if (child.type === 't') {
                                tArr.push(id)
                            }
                        }
                    }
                    if (vArr.length) {
                        command += ` -d ${vArr.join()}`
                    } else {
                        command += ` -D`
                    }
                    if (aArr.length) {
                        command += ` -a ${aArr.join()}`
                    } else {
                        command += ` -A`
                    }
                    if (tArr.length) {
                        command += ` -s ${tArr.join()}`
                    } else {
                        command += ` -S`
                    }
                    command += ` "${o.path}"`
                    sendMsg(`${o.name}开始处理. \n命令:${command}\n`)
                    const cmdRunPromise = (command, index, o) => {
                        return new Promise((resolve, reject) => {
                            const process = cmd.run(command, (err, data, stderr) => {
                                // if (err) {
                                //     return reject(err)
                                // }
                                resolve({err, data, stderr, command, index, o})
                            })
                            process.stdout.on('data', data => {
                                sendMsg(`${o.name}.${data}`)
                            })
                        })
                    }

                    // const cmdRun = util.promisify(cmd.run)
                    cmdRunPromises.push(cmdRunPromise(command, index, o))


                } catch (e) {
                    sendMsg(`${o.name}发生错误. \n信息:${e.message}`)
                }
            }
            Promise.all(cmdRunPromises).then((args) => {
                if (args && args.length) {
                    const mvPromises = []
                    for (let i = 0; i < args.length; i++) {
                        const {err, data, stderr, command: command, index, o} = args[i]
                        const newPath = `${o.path}.temp`
                        sendMsg(`${o.name}处理完成(${index + 1}/${filter.length}).`)
                        sendMsg(`${o.name}覆盖文件(${index + 1}/${filter.length}).`)

                        const mvPromise = (command, index, o) => {
                            return new Promise((resolve, reject) => {
                                mv(newPath, o.path, (err) => {
                                    resolve({err, command, index, o})
                                })
                            })
                        }
                        mvPromises.push(mvPromise(command, index, o))
                    }
                    Promise.all(mvPromises).then((args) => {
                        if (args && args.length) {

                            const writePromises = []
                            for (let i = 0; i < args.length; i++) {
                                const {err, command, index, o} = args[i]
                                if (!err) {
                                    sendMsg(`${o.name}覆盖完成(${index + 1}/${filter.length}).`)
                                    const remark = JSON.stringify({
                                        filename: o.path,
                                        command: command,
                                        date: moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'),
                                        oldSize: o.size,
                                        oldSizeFormat: o.sizeFormat
                                    }, null, 2)
                                    const writePromise = (o, remark) => {
                                        return new Promise((resolve, reject) => {
                                            fs.writeFile(`${o.path}.fixed`, remark, (err) => {
                                                resolve({err, o})
                                            })

                                        })
                                    }
                                    writePromises.push(writePromise(o, remark))

                                } else {
                                    sendMsg(`${o.name}覆盖错误(${index + 1}/${filter.length}).\n信息:${err}`)
                                }
                            }
                            Promise.all(writePromises).then((args) => {
                                if (args && args.length) {
                                    const mvPromises = []
                                    for (let i = 0; i < args.length; i++) {
                                        const {err, o} = args[i]

                                        if (!err) {
                                            const mvPromise = (o) => {
                                                return new Promise((resolve, reject) => {
                                                    mv(`${o.path}.mediainfo`, `${o.path}.mediainfo.${moment(Date.now()).format('YYYYMMDDHHmm')}`, (err) => {
                                                        resolve(err)
                                                    })
                                                })
                                            }
                                            mvPromises.push(mvPromise(o))
                                        } else {
                                            logger.error(err)
                                        }
                                    }
                                    Promise.all(mvPromises).then((err) => {
                                        if (!err) {
                                            logger.error(err)
                                        }
                                        runNext(indexs)
                                    })
                                } else {
                                    runNext(indexs)
                                }
                            })
                        } else {
                            runNext(indexs)
                        }
                    })
                } else {
                    runNext(indexs)
                }
            })
        } catch (e) {
            logger.error(e)
            sendMsg(e)
            runNext(indexs)
        }
    }
    runNext()
}

export function handleGetMediaInfo(event, path) {
    try {
        return fs.readFileSync(`${path}.mediainfo`, {encoding: 'UTF-8'});
    } catch (e) {
        logger.error(e)
        return null
    }
}

export async function handleGetMediaInfoXml(event, path) {
    try {
        const xml = fs.readFileSync(`${path.substring(0, path.lastIndexOf("."))}-mediainfo.xml`, {encoding: 'UTF-8'})
        if (xml) {
            const ps = (xml) => {
                return new Promise((resolve, reject) => {
                    parseString(xml, function (err, result) {
                        if (err) {
                            logger.error(err)
                        }
                        return resolve(JSON.stringify(result))
                    });
                })
            }
            return await ps(xml)
        } else {
            return null
        }

    } catch (e) {
        logger.error(e)
        return null
    }
}

export function handleGetFixed(event, path) {
    try {
        return fs.readFileSync(`${path}.fixed`, {encoding: 'UTF-8'});
    } catch (e) {
        logger.error(e)
        return null
    }
}

export async function handleGetNfo(event, path) {
    try {
        const nfo = fs.readFileSync(`${path.substring(0, path.lastIndexOf("."))}.nfo`, {encoding: 'UTF-8'})
        if (nfo) {
            const ps = (nfo) => {
                return new Promise((resolve, reject) => {
                    parseString(nfo, function (err, result) {
                        if (err) {
                            logger.error(err)
                        }
                        return resolve(JSON.stringify(result))
                    });
                })
            }
            return await ps(nfo)
        } else {
            return null
        }

    } catch (e) {
        logger.error(e)
        return null
    }
}

export function handleGetConf(event) {
    try {
        const homeDir = path.dirname(app.getPath('exe'))
        let confPath = homeDir
        if (process.platform === 'darwin') {
            confPath = `${homeDir}/conf.json`
        }
        if (process.platform === 'win32') {
            confPath = `${homeDir}\\conf.json`
        }
        return fs.readFileSync(confPath, {encoding: 'UTF-8'});
    } catch (e) {
        logger.error(e)
        return null
    }
}

export function handleGetTranslateConf(event) {
    try {
        const translate = fs.readFileSync(path.join(__static, 'zh_CN.txt'), {encoding: 'UTF-8'});
        return translate
    } catch (e) {
        logger.error(e)
        return null
    }
}

export function handleSaveMediaInfo(event, path, data) {
    fs.writeFile(`${path}.mediainfo`, data, () => {
        logger.info(`保存mediainfo文件成功：${path}`)
    })
}

export function initWasm() {
    const source = fs.readFileSync(path.join(__static, 'mediainfo/MediaInfoWasm.wasm'))
    const env = {
        memoryBase: 0, tableBase: 0, memory: new WebAssembly.Memory({
            initial: 256
        }), table: new WebAssembly.Table({
            initial: 0, element: 'anyfunc'
        })
    }
    const typedArray = new Uint8Array(source);
    WebAssembly.instantiate(typedArray, {
        env: env
    }).then(result => {
        // console.log(util.inspect(result, true, 0));
        // console.log(result.instance.exports._add(9, 9));
        mediainfo = result.instance.exports
    }).catch(e => {
        // error caught
        logger.error(e);
    });
}